﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TrackSystem.Contracts;
using TrackSystem.Entities.Extensions;
using TrackSystem.Entities.Models;
using TrackSystem.IO.Alarm;
using TrackSystem.IO.Data;
using TrackSystem.IO.Equip;
using TrackSystem.IO.Formula;
using TrackSystem.IO.Ports;
using TrackSystem.IO.Utils;

namespace TrackSystem.IO.Logics
{
    /// <summary>
    /// 逻辑处理工作类
    /// </summary>
    public class LogicFactory
    {
        /// <summary>
        /// 逻辑工程类实例句柄
        /// </summary>
        public static LogicFactory Instance { get; set; }

        /// <summary>
        /// 逻辑字典集合
        /// </summary>
        public ConcurrentDictionary<string, LogicItem> Items = new();

        /// <summary>
        /// ID号和逻辑名称对照表
        /// </summary>
        public ConcurrentDictionary<int, string> IdNameDictionary = new();

        /// <summary>
        /// 使能
        /// </summary>
        public static bool Enabled { get; protected set; }

        /// <summary>
        /// 设定运算周期ms
        /// </summary>
        public static int Interval { get; protected set; }

        /// <summary>
        /// 时间运算周期ms
        /// </summary>
        public static int Cycle { get; protected set; }

        /// <summary>
        /// 实际花费时间ms
        /// </summary>
        public static int Lapse { get; protected set; }

        /// <summary>
        /// 是否允许标志
        /// </summary>
        public bool Running { get; protected set; }

        /// <summary>
        /// 线程句柄
        /// </summary>
        private Thread thd;

        /// <summary>
        /// 构造函数
        /// </summary>
        static LogicFactory()
        {
            Instance = new LogicFactory();
            Instance.Initialize();
        }

        /// <summary>
        /// 创建函数
        /// </summary>
        private void Initialize()
        {
            Enabled = false;
            Interval = 100;
        }

        /// <summary>
        /// 卸载所有传感器
        /// </summary>
        public void Unload()
        {
            if (Running)
            {
                Running = false;
                thd.Join();
            }
            foreach (var item in Items.Values)
            {
                if (EquipFactory.Instance.TryGetValue(item.EquipId, out var equip))
                {
                    equip?.Parts?.TryRemove(item.Name, out _);

                }
            }
            Items.Clear();
            IdNameDictionary.Clear();
        }

        /// <summary>
        /// 初始化函数
        /// </summary>
        /// <param name="logicList"></param>
        /// <param name="varNames"></param>
        /// <returns></returns>
        public async Task<ResultMsg> Load(IRepositoryWrapper wrapper)
        {
            Enabled = false;

            // 释放所有资源
            Unload();

            string sError = "";

            var logicList = await wrapper.Logic.GetAllListAsync();
            var regs = await wrapper.Var.GetAllListAsync();
            var varNames = regs.ToDictionary(a => a.Name, b => b.DataType);

            foreach (LogicTable logicItem in logicList)
            {
                var sTemp = logicItem.ClacateFormula.Replace('\n', ' ').Replace('\r', ' ');

                try
                {
                    LogicItem attr = new LogicItem()
                    {
                        Name = logicItem.Name,
                        Enabled = logicItem.Enabled,
                        condFormula = logicItem.ConditionFormula,
                        clacFormula = logicItem.ClacateFormula,
                        UpdateWenChanged = logicItem.UpdateWhenChanged,
                        condStack = new Stack<ExprItem>(),
                        clacStack = new Stack<ExprItem>(),
                        lstFormual = new List<FormulaItem>(),
                        OutRegsName = new List<string>(),
                        lstValue = new List<OperandDef>(),
                        lastlstValue = new List<OperandDef>(),
                        EquipId = logicItem.equipId
                    };

                    //1 输出寄存器变量生成
                    //string[] regItems = logicItem.ResultReg.Split(',');
                    //foreach (string item in regItems)
                    //    attr.OutRegsName.Add(item.Trim());

                    //2 条件表达式
                    string str = ClacuationFormula.PreTreat(logicItem.ConditionFormula).Message ??="";
                    List<string> lstResult = ClacuationFormula.Segment(str);
                    ClacuationFormula.Parse(lstResult, attr.condStack, varNames);

                    //str = ClacuationFormula.PreTreat(logicItem.ClacateFormula);
                    //lstResult = ClacuationFormula.Segment(str);
                    //ClacuationFormula.Parse(lstResult, attr.clacStack, varNames);
                    // 初始化

                    //3 计算表达式
                    //3.1 预处理
                    var preResult = PageAnalysis.PrePageToLine(logicItem.ClacateFormula, out var lstFormula);
                    if (!preResult.Result)
                        continue;

                    attr.lstStrFormual = new();

                    //3.2 分段处理
                    foreach (var item in lstFormula)
                    {
                        var segResult = PageAnalysis.ElementSegmentation(item, out var lstSegment, out string regName);  // 分段
                        if (!segResult.Result)
                        {
                            continue;
                        }

                        Stack<ExprItem> stack = new Stack<ExprItem>();
                        var parResult = ClacuationFormula.Parse(lstSegment, stack, varNames);  // 转换为中缀表达式
                        if (!parResult.Success)
                        {
                            continue;
                        }

                        // 加入目前值及上次的值
                        if (varNames.TryGetValue(regName, out var type))
                        {
                            FormulaItem formulaItem = new() { clacStack = stack, OutVar = regName };
                            attr.lstStrFormual.Add(item);               // 表达式解析结果
                            attr.lstFormual.Add(formulaItem);           // 表达式字符串

                            attr.lstValue.Add(new OperandDef(type));    // 表达式计算结果
                            attr.lastlstValue.Add(new OperandDef(type));// 表达式上次计算结果
                        }
                    }
                    
                    // 综合计算
                    Items.TryAdd(logicItem.Name, attr);
                    IdNameDictionary.TryAdd(logicItem.Id, logicItem.Name);
                    if (EquipFactory.Instance.TryGetValue(logicItem.equipId, out EquipItem? equipItem))
                    {
                        equipItem?.TryAddLogic(attr);
                    }
                }
                catch (Exception)
                {
                    sError = logicItem.Name + " ";
                }
            }

            thd = new Thread(WorkerThread)
            {
                IsBackground = true,
            };
            Enabled = true;
            Running = true;
            thd.Start();

            if (sError == "")
                return ResultMsg.Succ("逻辑表达式初始化成功");
            else
                return ResultMsg.Fail($"逻辑表达式初始化失败, {sError}");
        }

        /// <summary>
        /// 工作者线程
        /// </summary>
        private void WorkerThread()
        {
            int startTicks, deltaTicks, temp;
            int lastTicks = Environment.TickCount;
            
            while (Running)
            {
                // 如果没有使能 这不进行逻辑处理
                if (!Enabled)
                {
                    Thread.Sleep(Interval);
                    continue;
                }
                startTicks = Environment.TickCount;
                // ------工作者线程开始---------------------------------------------

                foreach (var item in Items.Values)
                {
                    try
                    {
                        // 未使能
                        if (!item.Enabled)
                            continue;

                        // 计算条件表达式
                        item.condValue = ClacuationFormula.Evaluate(item.condStack);

                        // 条件不为零，才能进行计算
                        if (item.condValue.bVal)
                        {
                            for (int i = 0; i < item.lstFormual.Count; i++)
                            {
                                item.lastlstValue[i] = item.lstValue[i];
                                item.lstValue[i] = ClacuationFormula.Evaluate(item.lstFormual[i].clacStack);

                                // 和上次计算的结果相差太小
                                //if (Math.Abs(item.lastlstValue[i] - item.lstValue[i]) < double.Epsilon && item.UpdateWenChanged)
                                if (item.lastlstValue[i].Equals(item.lstValue[i]) && item.UpdateWenChanged)
                                        continue;

                                // 输出结果到寄存器
                                RegFactory.Instance[item.lstFormual[i].OutVar] = item.lstValue[i];
                            }
                        }

                    }
                    catch (Exception ex)
                    {
                        AlarmFactory.Instance.Insert(ex.Message, AlarmCategory.LOGIC, item.Name, 0);
                    }
                }

                // ------工作者线程结束---------------------------------------------
                temp = Environment.TickCount;
                Cycle = temp - lastTicks;
                Lapse = temp - startTicks;
                lastTicks = temp;
                deltaTicks = Interval - Lapse - 5;

                if (deltaTicks > 0)
                    Thread.Sleep(deltaTicks);
            }

        }    
    }


}
